package toy.keli.edic.data.config

import android.os.Handler
import androidx.collection.arrayMapOf
import androidx.compose.runtime.getValue
import androidx.compose.runtime.mutableStateOf
import androidx.compose.runtime.setValue
import com.fasterxml.jackson.annotation.JsonIgnore
import com.fasterxml.jackson.annotation.JsonProperty
import toy.keli.edic.data.UserStatus
import toy.keli.edic.data.model.Article
import toy.keli.edic.data.model.WordExtend
import toy.keli.edic.domain.model.WordModel
import toy.keli.edic.ui.history.BookHistroy
import toy.keli.edic.ui.home.HomeEvents
import toy.keli.edic.ui.main.extend.MainRun
import toy.keli.edic.ui.main.extend.bgRun
import toy.keli.edic.ui.main.extend.setTimeout
import toy.keli.edic.ui.navigation.NavScreen
import toy.keli.edic.util.ActivityRun
import toy.keli.edic.util.FileUtil
import kotlinx.coroutines.CoroutineScope
import kotlinx.coroutines.CoroutineStart
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.GlobalScope
import kotlinx.coroutines.async
import kotlinx.coroutines.flow.MutableStateFlow
import kotlinx.coroutines.launch
import kotlinx.coroutines.plus
import kotlinx.coroutines.runBlocking
import kotlinx.coroutines.withContext
import kotlin.math.max

data class BookConf (
    @JsonProperty("name")
    var name: String = "",
    @JsonProperty("id")
    val id: Int=0,
    @JsonProperty("intime")
    val intime: Long=0,
    @JsonProperty("chapterName")
    var chapterName: String = "",
    @JsonProperty("pIndex")
    var pIndex: Int=0,
) {

    @JsonIgnore
    var index:Int = 0;
    @JsonIgnore
    var size:Int = 0;
    @JsonIgnore
    var word:String = "";
    @JsonIgnore
    var ch:String = "";
    @JsonIgnore
    var lastBookId =0
    @JsonIgnore
    public var wordMode: WordModel? =null
    class Events{
        var onWordChange:BookConf.(word:WordModel)->Unit = {}
        var onChaptersChange:BookConf.()->Unit = {}
        var onBookChange:BookConf.()->Unit = {}
    }
    companion object {
        val  TAG = "Book"
        val openedBook = mutableStateOf("Book")

        lateinit var instance:BookConf
        val event = Events()
        val upStatus: MutableStateFlow<Int> = MutableStateFlow(0)
        var doc = ""
        var chapters = arrayListOf<String>()

        var chapterMapWords = arrayMapOf<String,List<String>>()
        var words by mutableStateOf(listOf<WordModel>())
        var chapterWordModels = listOf<WordModel>()
        var inited = false
        fun userBook(v: BookConf?=null): BookConf {
            if(v!=null) {
                UserStatus().setData("BookConf",v)
                return v
            }
            val rt = UserStatus().getData("BookConf", BookConf::class.java) ?: BookConf()
            return rt
        }
        public fun setBook(id:Int) {
            val aModel = Article.find(id)
            if(aModel!=null) {
                val nowBook = BookConf(aModel.name, aModel.id, aModel.intime)
                setBook(nowBook,true)
            }
        }
        /**
         * 设置book
         * bookConf 要设置的配置
         * saveDo   是不是保存配置
         */
        public fun setBook(bookConf: BookConf?=null, saveDo:Boolean = false) {
            instance = if(bookConf==null) userBook() else bookConf
            if(saveDo) {
                userBook(instance)
            }
            onOpenBook(instance)
        }
        private fun onOpenBook(bc: BookConf) {
            var obn = bc.name.replace(Regex("\\.\\w+$"),"")
            if(obn.length>4) obn=obn.substring(0,4)+".."
            if(obn.length>0)
            openedBook.value = obn
            event.onBookChange.invoke(instance)
        }

        fun selectBook() {
            NavScreen.openJdc(-1)
        }
        val onBookChange  = {f:BookConf.()->Unit ->  event.onBookChange =f }
        val onChaptersChange  : (BookConf.()->Unit) -> Unit = { event.onChaptersChange = it }
        fun onWordChange (f:BookConf.(WordModel)->Unit) { event.onWordChange =f}
        fun initOnce() {
            if(!inited) {
                instance = userBook()
                onOpenBook(instance)
                inited=true
            }
        }

        fun setDefBook() {
            setBook(BookConf("书本01",0,0,"章节01"))
        }
    }
    fun initArticle()  {
        if(lastBookId== instance.id && instance.size>0){
            return
        }
        lastBookId = instance.id

        Article.finds(listOf( instance.id),true){
            if(it.size==0) return@finds
            val a = it.first()
            doc = a.content
            if(doc.length>150000) doc = doc.substring(0,150000)
            initByData(doc)
            //usBook(this)
        }
    }
    //文章类型是不是单词列表
    fun typeIsWordList():Boolean{
        return !doc.matches(Regex("[\\.;\"]"))
    }
    //是不是中文段落
    fun perIsCh(per:String):Boolean{
        return Regex("[\u4E00-\u9FA5]+").containsMatchIn(per)
    }
    //获取到段落中单词
    fun gPerWords(mapWords:String) : List<String>{
        if(typeIsWordList()) {
            return mapWords.split(Regex(",|，|\\s+"))
                .map{
                    it.trim()
                }.filter {
                    it.length>0
                }.toHashSet().toList()
        }else {
            var rt = mapWords.split(Regex(",|，|\\s+|\\.|!|\"|:"))
                .map {
                    it.trim()
                    it.replace(Regex("^\\W+|\\W+$"), "")
                }.filter {
                    it.length > 0 && !it.matches(Regex("^\\d.+"))
                }
            rt = rt.toHashSet().toList()
            return rt;
        }
    }
    fun initByData(doc:String){
        var beforeLine = ""
        var beforeChapter = ""
        var mapWords = ""
        words = listOf<WordModel>()
        chapters.clear()
        chapterMapWords.clear()
        index=0
        doc.split(Regex("\\r\\n|\\r|\\n")).map{it.trim()}.forEach{
            if(it.length>0) {
                //当前行的长度大于0 并且上面是个空行长度小于50或Chapter开头就认为是一个章节
                if ((beforeLine.length == 0 && it.length<50 && !beforeChapter.startsWith("Chapter"))|| it.startsWith("Chapter ")) {
                    if (mapWords.length > 0) {
                        chapterMapWords[beforeChapter] = gPerWords(mapWords)
                        mapWords = ""
                    }
                    chapters.add(it)
                    beforeChapter = it
                } else {
                    if(!perIsCh(it))
                    mapWords += "," + it
                }
            }
            beforeLine = it
        }
        if(mapWords.length>0) {
            chapterMapWords[beforeChapter] = gPerWords(mapWords)
        }
        if(chapters.size ==1 && name!="历史记录页"){
            val first = chapters[0]
            chapters[0] = "defaultChapter"
            val newList = arrayListOf<String>()
            first.split(Regex(",|，|\\s+")).map{it.trim()}.filter { it.length>0 }.filter { newList.add(it) }
            if(chapterMapWords.size>0) {
                newList.addAll(chapterMapWords[first]!!)
            }
            chapterMapWords[chapters[0]] = newList
            chapterMapWords.remove(first)
        }
        if(chapters.size>0 && !chapters.contains(chapterName)) {
            chapterName = chapters[0]
        }
        save(chapterName,false)
    }

    fun save(chapterName: String="",doSave:Boolean=true) {
//        //文章中没有此数据就不要保存防止下一次进来没数据
//        if(chapterName!="defaultChapter" && doc.indexOf(chapterName) == -1) {
//            return
//        }
        if(chapterName.length>0) {
            this.chapterName = chapterName
        }
        wordMode=null
        index=0
        var mWords = chapterMapWords[chapterName]
        if(mWords!=null) {
            bgRun{
                chapterWordModels = Article.getWords(mWords)
                upWords(chapterWordModels)
            }
        }

        if(doSave) {
            userBook(this)
        }
        upStatus.value++
    }

    fun upWords(wds:List<WordModel>){
        words = wds
        wordMode = null
        next(0)
        event.onChaptersChange.invoke(instance)
    }

    fun next(d:Boolean):Boolean {
        val map = arrayMapOf(true to 1,false to -1)
        return next(map[d]!!)
    }

    fun next(n:Int=1,autoReset:Boolean=true):Boolean {
        if(n==1 && !HomeEvents.onNextWordBefore()){
            return true
        }
        this.index+=n
        if(words.size==0 || index<0){
            if(index<0) {
                index = 0
                ActivityRun.msg("已经是第一个单词了！")
            }
            return false
        }
        if(index>= words.size){
            if(!autoReset) return false
            index= 0
            ActivityRun.msg("已经到最后单词并重新开始了。")
        }
        val word  =
            if(n==0 && this.wordMode!=null && !(this.wordMode!!.word in words.map{it.word}))
                this.wordMode
            else
                words[index]
        this.size = words.size
        next(word!!)
        if(index<size && index>=0) {
            return true
        }
        return false
    }

    fun next(word: WordModel,newIndex:Int=0) {
        this.word = word.word
        wordMode = word
        if(newIndex>0) index = newIndex
        if (word != null && word.ch != null) {
            this.ch = word.ch!!
        }
        //保存单词进度
        BookHistroy.lastWord(word.word,index)

        event.onWordChange.invoke(instance, word)
    }

    fun setWordByString(word:String) {
        index = max(0,words.map{it.word}.indexOf(word))
        wordMode = null
        next(0)
    }

    fun setContent(s: String, hashData: LinkedHashMap<String, List<String>>) {
        name = s.replace(regex = Regex("\\.\\w+$"),"")
        val rows=hashData.map {
            it.key +"\n"+ it.value.joinToString ( "," )
        }.joinToString ("\n\n" )
        initByData(rows)
    }

    fun pid(): Int {
        return Article.find(id)?.cid ?: 0
    }

    fun reset() {
        index=0
        next(0)
    }

    fun lastScrollIndex(index:Int=-1): Int {
        if(pIndex==index) return index
        if(index>-1) {
            pIndex = index
            userBook(this)
        }
        return pIndex
    }
}
